package si.banst.tecajnice.ejb;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import si.banst.tecajnice.ejb.napake.NapakaPriPosodobitvi;
import si.banst.tecajnice.ejb.napake.NapakaPriPovprasevanju;
import si.banst.tecajnice.ejb.napake.NapakaPriPreracunu;
import si.banst.tecajnice.ejb.napake.NapakaPriZapisu;
import si.banst.tecajnice.ejb.prestrezniki.SledenjeZahtevam;
import si.banst.tecajnice.entitete.Ponder;
import si.banst.tecajnice.entitete.PonderID;
import si.banst.tecajnice.entitete.StatusAktivnosti;
import si.banst.tecajnice.entitete.Tecaj;
import si.banst.tecajnice.entitete.TecajID;
import si.banst.tecajnice.entitete.Tecajnica;
import si.banst.tecajnice.entitete.TecajnicaID;
import si.banst.tecajnice.entitete.Valuta;
import si.banst.tecajnice.entitete.VrstaTecajnice;

/**
 * Session Bean implementation class TecajniceBean
 */
@Stateless
@Interceptors(SledenjeZahtevam.class)
@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun", "Referent", "PoslovniPartnerji" })
public class TecajniceBean implements TecajniceBeanLocal, TecajniceBeanRemote {

	private static final Logger logger = Logger.getLogger(TecajniceBean.class
			.getName());

	private static final int SIFRA_VRSTE_TECAJNICE_BSI = 1;

	@PersistenceContext(unitName = "tecajnice-jpa")
	private EntityManager em;

	@EJB
	private PonderjiBeanLocal ponderjiBean;

	@Resource
	private SessionContext sessionContext;

	/**
	 * Default constructor.
	 */
	public TecajniceBean() {
		super();
	}

	@PostConstruct
	public void init() {
		logger.fine("Preverjam povezavos s persistečno enoto");
		if (em == null) {
			logger.severe("Povezava z persistencno enoto tecajnice-jpa ni vzpostavljena.");
			throw new EJBException(
					"Povezava z persistencno enoto tecajnice-jpa ni vzpostavljena.");
		}
	}

	@Override
	public List<Tecajnica> vrniVseTecajnice() throws NapakaPriPovprasevanju {
		try {
			@SuppressWarnings("unchecked")
			List<Tecajnica> tecajnice = em.createNamedQuery("vrniVseTecajnice")
					.getResultList();
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecajnice;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	public Tecajnica vrniTecajnico(TecajnicaID tecajnicaID)
			throws NapakaPriPovprasevanju {
		try {
			Tecajnica tecajnica = em.find(Tecajnica.class, tecajnicaID);
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecajnica;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	public Tecajnica vrniZadnjoTecajnico(int sifraVrsteTecajnice)
			throws NapakaPriPovprasevanju {
		try {
			Query povprasevanje = em
					.createNamedQuery("vrniDatumZadnjeTecajnice");
			povprasevanje.setParameter("sifraVrsteTecajnice",
					sifraVrsteTecajnice);
			povprasevanje.setMaxResults(1);
			@SuppressWarnings("unchecked")
			List<Date> urejeniDatumiTecajnic = povprasevanje.getResultList();
			if (urejeniDatumiTecajnic.isEmpty())
				return null;

			TecajnicaID tecajnicaID = new TecajnicaID();
			tecajnicaID.setDatumTecajnice(urejeniDatumiTecajnic.get(0));
			tecajnicaID.setSifraVrsteTecajnice(sifraVrsteTecajnice);

			Tecajnica tecajnica = em.find(Tecajnica.class, tecajnicaID);
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecajnica;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
	public void zapisiTecajnico(Tecajnica tecajnica) throws NapakaPriZapisu {
		try {
			em.persist(tecajnica);
			logger.fine("Zapis uspešno vstavljen.");
		} catch (Exception e) {
			logger.severe("Napaka pri zapisovanju." + e.getMessage());
			throw new NapakaPriZapisu(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
	public void posodobiTecajnico(Tecajnica tecajnica)
			throws NapakaPriPosodobitvi {
		try {
			em.merge(tecajnica);
			logger.fine("Zapis uspešno posodobljen.");
		} catch (Exception e) {
			logger.severe("Napaka pri posodobitvi." + e.getMessage());
			throw new NapakaPriPosodobitvi(e);
		}
	}

	@Override
	@RolesAllowed({ "ReferentZaPreracun" })
	public Tecajnica preracunajTecajnico(int sifraVrsteTecajnice,
			Date datumTecajnice, Boolean ponovnoPreracunajObstojece)
			throws NapakaPriPreracunu {
		try {

			VrstaTecajnice vrstaTecajnice = vrniVrstoTecajnice(sifraVrsteTecajnice);
			if (vrstaTecajnice == null)
				throw new NapakaPriPreracunu(
						"Vrsta tečajnice za preračun ne obstaja.");

			if (vrstaTecajnice.getOsnovaZaPreracun() == null)
				throw new NapakaPriPreracunu(
						"Osnovna vrsta tečajnice za preračun ne obstaja.");

			Tecajnica osnovnaTecajnica = vrniTecajnico(new TecajnicaID(
					datumTecajnice, vrstaTecajnice.getOsnovaZaPreracun()
							.getSifraVrsteTecajnice()));

			Tecajnica tecajnica = vrniTecajnico(new TecajnicaID(datumTecajnice,
					sifraVrsteTecajnice));

			if (tecajnica == null) {
				logger.fine("Tečajnica še ne obstaja.");
				tecajnica = new Tecajnica();
				TecajnicaID tecajnicaID = new TecajnicaID();
				tecajnica.setId(tecajnicaID);
				tecajnicaID.setDatumTecajnice(datumTecajnice);
				tecajnicaID.setSifraVrsteTecajnice(sifraVrsteTecajnice);
				tecajnica.setDatumCasPreracuna(new Date());
				tecajnica.setReferentZaPreracun(sessionContext
						.getCallerPrincipal().getName());
				tecajnica.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
				tecajnica.setVrstaTecajnice(vrstaTecajnice);
				zapisiTecajnico(tecajnica);
				logger.fine("Zapisana nova tecajnica.");
			}

			int steviloNovihTecajev = 0;
			int steviloPosodobljenihTecajev = 0;

			for (Tecaj osnovniTecaj : osnovnaTecajnica.getTecaji()) {

				Valuta valuta = osnovniTecaj.getValuta();

				TecajID tecajID = new TecajID();
				tecajID.setDatumTecajnice(datumTecajnice);
				tecajID.setSifraValute(valuta.getSifraValute());
				tecajID.setSifraVrsteTecajnice(sifraVrsteTecajnice);
				Tecaj tecaj = vrniTecaj(tecajID);

				if (tecaj == null) {
					tecaj = new Tecaj();
					tecaj.setId(tecajID);
					tecaj.setEnotaTecaja(new BigDecimal(1.0));
					tecaj.setReferent(sessionContext.getCallerPrincipal()
							.getName());
					tecaj.setSrednjiTecaj(null);
					tecaj.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
					tecaj.setTecajnica(tecajnica);
					tecaj.setValuta(valuta);

					PonderID ponderID = new PonderID();
					ponderID.setSifraValute(valuta.getSifraValute());
					ponderID.setSifraVrsteTecajnice(sifraVrsteTecajnice);
					Ponder ponder = ponderjiBean.vrniPonder(ponderID);
					logger.fine("Ponder ne obstaja.");
					if (ponder == null)
						continue;

					BigDecimal vrednost = osnovniTecaj.getSrednjiTecaj()
							.multiply(ponder.getOdmikNakupnegaTecaja());
					tecaj.setNakupniTecaj(vrednost.setScale(4,
							BigDecimal.ROUND_HALF_UP));

					tecaj.setSrednjiTecaj(null);

					vrednost = osnovniTecaj.getSrednjiTecaj().multiply(
							ponder.getOdmikProdajnegaTecaja());
					tecaj.setProdajniTecaj(vrednost.setScale(4,
							BigDecimal.ROUND_HALF_UP));

					zapisiTecaj(tecaj);
					tecajnica.getTecaji().add(tecaj);
					steviloNovihTecajev++;
					logger.fine("Nov tecaj zapisan.");
				} else if (ponovnoPreracunajObstojece) {
					PonderID ponderID = new PonderID();
					ponderID.setSifraValute(valuta.getSifraValute());
					ponderID.setSifraVrsteTecajnice(sifraVrsteTecajnice);
					Ponder ponder = ponderjiBean.vrniPonder(ponderID);
					logger.fine("Ponder ne obstaja.");
					if (ponder == null)
						continue;

					BigDecimal vrednost = osnovniTecaj.getSrednjiTecaj()
							.multiply(ponder.getOdmikNakupnegaTecaja());
					tecaj.setNakupniTecaj(vrednost.setScale(4,
							BigDecimal.ROUND_HALF_UP));

					tecaj.setSrednjiTecaj(null);

					vrednost = osnovniTecaj.getSrednjiTecaj().multiply(
							ponder.getOdmikProdajnegaTecaja());
					tecaj.setProdajniTecaj(vrednost.setScale(4,
							BigDecimal.ROUND_HALF_UP));

					posodobiTecaj(tecaj);
					steviloPosodobljenihTecajev++;
					logger.fine("Tecaj posodobljen");
				}
			}
			logger.info("Tečajnica uspešno preračunana. Stevilo novih tečajev: "
					+ steviloNovihTecajev
					+ " Stevilo posodobljenih tečajev: "
					+ steviloPosodobljenihTecajev);
			return tecajnica;
		} catch (Exception e) {
			logger.severe("Napaka pri preračunu." + e.getMessage());
			throw new NapakaPriPreracunu(e);
		}
	}

	@Override
	public List<Tecaj> vrniVseTecaje() throws NapakaPriPovprasevanju {
		try {
			@SuppressWarnings("unchecked")
			List<Tecaj> tecaj = em.createNamedQuery("vrniVseTecaje")
					.getResultList();
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecaj;
		} catch (Exception e) {
			logger.severe("Napaka pri povpraševanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent" })
	public List<Tecaj> vrniVseNeaktivneTecaje() throws NapakaPriPovprasevanju {
		try {
			
			Query query = em.createNamedQuery("vrniVseNeaktivneTecaje");
			@SuppressWarnings("unchecked")
			List<Tecaj> tecaj = query.getResultList();
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecaj;
		} catch (Exception e) {
			logger.severe("Napaka pri povpraševanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	public Tecaj vrniTecaj(TecajID tecajID) throws NapakaPriPovprasevanju {
		try {
			Tecaj tecaj = em.find(Tecaj.class, tecajID);
			logger.fine("Povpraševanje uspešno izvedeno.");
			return tecaj;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
	public void zapisiTecaj(Tecaj tecaj) throws NapakaPriZapisu {
		try {
			em.persist(tecaj);
			logger.fine("Zapis uspešno vstavljen.");
		} catch (Exception e) {
			logger.severe("Napaka pri zapisovanju." + e.getMessage());
			throw new NapakaPriZapisu(e);
		}

	}

	@Override
	@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
	public void posodobiTecaj(Tecaj tecaj) throws NapakaPriPosodobitvi {
		try {
			em.merge(tecaj);
			logger.fine("Zapis uspešno posodobljen.");
		} catch (Exception e) {
			logger.severe("Napaka pri posodobitvi." + e.getMessage());
			throw new NapakaPriPosodobitvi(e);
		}

	}

	@Override
	public List<VrstaTecajnice> vrniVseVrsteTecajnic()
			throws NapakaPriPovprasevanju {
		try {

			@SuppressWarnings("unchecked")
			List<VrstaTecajnice> vrsteTecajnic = em.createNamedQuery(
					"vrniVseVrsteTecajnic").getResultList();
			logger.fine("Povpraševanje uspešno izvedeno.");
			return vrsteTecajnic;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	public VrstaTecajnice vrniVrstoTecajnice(int sifraVrsteTecajnice)
			throws NapakaPriPovprasevanju {
		try {
			VrstaTecajnice vrstaTecajnice = em.find(VrstaTecajnice.class,
					sifraVrsteTecajnice);
			logger.fine("Povpraševanje uspešno izvedeno.");
			return vrstaTecajnice;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
	public VrstaTecajnice vrniVrstoTecajniceBSi() throws NapakaPriPovprasevanju {
		try {
			VrstaTecajnice vrstaTecajnice = em.find(VrstaTecajnice.class,
					SIFRA_VRSTE_TECAJNICE_BSI);
			logger.fine("Povpraševanje uspešno izvedeno.");
			return vrstaTecajnice;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju." + e.getMessage());
			throw new NapakaPriPovprasevanju(e);
		}
	}

	@Override
//	@RolesAllowed({ "OdgovorniReferent" })
	public void zapisiVrstoTecajnice(VrstaTecajnice vrstaTecajnice)
			throws NapakaPriZapisu {
		try {
			em.persist(vrstaTecajnice);
			logger.fine("Zapis uspešno vstavljen.");
		} catch (Exception e) {
			logger.severe("Napaka pri zapisovanju." + e.getMessage());
			throw new NapakaPriZapisu(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent" })
	public void posodobiVrstoTecajnice(VrstaTecajnice vrstaTecajnice)
			throws NapakaPriPosodobitvi {
		try {
			em.merge(vrstaTecajnice);
			logger.fine("Zapis uspešno posodobljen");
		} catch (Exception e) {
			logger.severe("Napaka pri posodobitvi." + e.getMessage());
			throw new NapakaPriPosodobitvi(e);
		}
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent" })
	public void zapisOsnovnihVrstTecajnic() throws NapakaPriZapisu {
		try {
			VrstaTecajnice vrstaTecajniceBSi = new VrstaTecajnice();
			vrstaTecajniceBSi.setDatumCasSpremembe(new Date());
			vrstaTecajniceBSi
					.setNazivVrsteTecajnice("Tečajnice Banke Slovenije");
			vrstaTecajniceBSi.setOsnovaZaPreracun(null);
			vrstaTecajniceBSi.setReferent(sessionContext.getCallerPrincipal()
					.getName());
			vrstaTecajniceBSi.setSifraVrsteTecajnice(1);
			vrstaTecajniceBSi.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
			logger.fine("Zapisujem vrsto tečajnice Banke Slovenije");
			zapisiVrstoTecajnice(vrstaTecajniceBSi);

			VrstaTecajnice menjalniskaVrstaTecajnice = new VrstaTecajnice();
			menjalniskaVrstaTecajnice.setDatumCasSpremembe(new Date());
			menjalniskaVrstaTecajnice
					.setNazivVrsteTecajnice("Menjalniške tečajnice");
			menjalniskaVrstaTecajnice.setOsnovaZaPreracun(vrstaTecajniceBSi);
			menjalniskaVrstaTecajnice.setReferent(sessionContext
					.getCallerPrincipal().getName());
			menjalniskaVrstaTecajnice.setSifraVrsteTecajnice(2);
			menjalniskaVrstaTecajnice
					.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
			logger.fine("Zapisujem menjalniške tečajnice.");
			zapisiVrstoTecajnice(menjalniskaVrstaTecajnice);

			VrstaTecajnice konverzijskaVrstaTecajnice = new VrstaTecajnice();
			konverzijskaVrstaTecajnice.setDatumCasSpremembe(new Date());
			konverzijskaVrstaTecajnice
					.setNazivVrsteTecajnice("Konverzijske tečajnice");
			konverzijskaVrstaTecajnice.setOsnovaZaPreracun(vrstaTecajniceBSi);
			konverzijskaVrstaTecajnice.setReferent(sessionContext
					.getCallerPrincipal().getName());
			konverzijskaVrstaTecajnice.setSifraVrsteTecajnice(3);
			konverzijskaVrstaTecajnice
					.setStatusAktivnosti(StatusAktivnosti.AKTIVEN);
			logger.fine("Zapisujem vrsto konverzijskih tečajnic.");
			zapisiVrstoTecajnice(konverzijskaVrstaTecajnice);
		} catch (NapakaPriZapisu e) {
			logger.severe("Napaka pri zapisovanju vrste tečajnic. "
					+ e.getMessage());
			throw new NapakaPriZapisu("Napaka pri zapisu VrstTečajnic.", e);
		}

	}

	@Override
	public List<Tecaj> vrniTecaje(List<TecajID> tecajID)
			throws NapakaPriPovprasevanju {
		List<Tecaj> tecaji = new ArrayList<Tecaj>();
		for (TecajID id : tecajID) {
			Tecaj tecaj = vrniTecaj(id);
			if (tecaj != null)
				tecaji.add(tecaj);
		}
		return tecaji;
	}

	@Override
	@RolesAllowed({ "OdgovorniReferent", "ReferentZaPreracun" })
	public void posodobiTecaje(List<Tecaj> tecaji) throws NapakaPriPosodobitvi {
		for (Tecaj tecaj : tecaji)
			posodobiTecaj(tecaj);

	}

}
